Rust logoRust Korea
홈매뉴얼커뮤니티검색로그인
<- 시리즈 목록

1장. Axum이란 무엇인가? - Rust 웹 생태계의 이해

약 13분 읽기

이 장에서는 Axum이 어떤 웹 프레임워크인지, 왜 Rust 생태계에서 주목받고 있는지, 그리고 다른 프레임워크들과 비교했을 때 어떤 장점을 가지는지 살펴봅니다. 웹 개발을 처음 시작하는 분들도 자연스럽게 이해할 수 있도록, 기본 개념부터 차근차근 설명하겠습니다.

Axum(액섬으로 발음합니다)은 Rust 프로그래밍 언어로 작성된 HTTP 라우팅 및 요청 처리 라이브러리입니다. tokio-rs 조직이 관리하는 이 프로젝트는 GitHub에서 27,000개 이상의 별을 받으며 Rust 웹 생태계에서 가장 인기 있는 프레임워크 중 하나로 자리 잡았습니다. 핵심 철학은 두 가지입니다. 바로 ’ergonomics(사용성)’와 ’modularity(모듈성)’입니다.

1.1 웹 프레임워크란 무엇인가?

웹 프레임워크는 웹 애플리케이션을 개발할 때 반복적으로 필요한 기능들을 미리 구현해둔 도구 모음입니다. HTTP 요청을 받아 적절한 함수로 전달하고(라우팅), 요청 데이터를 파싱하고, 응답을 생성하는 등의 작업을 처리합니다. 프레임워크가 없다면 개발자는 TCP 소켓부터 직접 다뤄야 하므로, 실제 비즈니스 로직에 집중하기 어렵습니다.

Rust 생태계에는 여러 웹 프레임워크가 존재합니다. 가장 잘 알려진 것들은 Actix-web, Rocket, Warp, 그리고 이 책의 주제인 Axum입니다. 각각 장단점이 있지만, Axum은 특히 tower 생태계와의 완벽한 통합, 직관적인 API, 그리고 타입 안정성을 강조합니다.

【참고】 웹 프레임워크를 처음 접하는 독자라면, 프레임워크가 해주는 일은 ’HTTP 요청이 들어왔을 때 어떤 코드를 실행할지 결정하고, 그 코드가 결과를 내놓으면 HTTP 응답으로 변환해주는 것’이라고 이해하시면 됩니다.

1.2 Axum의 핵심 특징

Axum은 다음 다섯 가지를 핵심 기능으로 내세웁니다. 각각이 왜 중요한지 하나씩 살펴보겠습니다.

  1. 매크로 없는(macro-free) API로 요청을 핸들러에 라우팅합니다.
  2. 추출자(extractor)를 사용한 선언적 요청 파싱을 지원합니다.
  3. 단순하고 예측 가능한 에러 처리 모델을 제공합니다.
  4. 최소한의 보일러플레이트로 응답을 생성할 수 있습니다.
  5. tower 및 tower-http 생태계의 미들웨어/서비스/유틸리티를 완전히 활용합니다.

1.2.1 매크로 없는 API — 왜 중요한가?

많은 프레임워크가 라우트를 정의할 때 매크로를 사용합니다. 예를 들어 Spring Boot의 @GetMapping이나 Rocket의 #[get(“/”)]가 그런 방식입니다. 매크로는 직관적이지만, 러스트 컴파일러가 검사하기 어렵고, IDE 자동 완성이 제한적이며, 런타임 오류를 발생시킬 수 있습니다.

Axum은 일반 Rust 함수를 그대로 핸들러로 사용합니다. 라우트는 메서드 체이닝으로 정의하므로, 컴파일러가 모든 타입을 검사합니다. 다음 예를 비교해 보세요.

// ===== Axum 방식: 매크로 없음 =====
// 라우트 정의는 일반 함수 호출로 이루어집니다.
use axum::{routing::get, Router};

let app: Router = Router::new()
    // "/" 경로에 GET 요청이 오면 root 함수를 실행하라는 의미입니다.
    .route("/", get(root))
    // "/users" 경로에 POST 요청이 오면 create_user를 실행합니다.
    .route("/users", post(create_user));

// 핸들러는 그냥 async 함수입니다. 특별한 어노테이션이 필요 없습니다.
async fn root() -> &'static str {
    "Hello, World!"
}

Axum 방식의 가장 큰 장점은 IDE 지원이 완벽하다는 것입니다. rust-analyzer가 모든 타입을 추론할 수 있어, 자동 완성과 리팩토링이 자연스럽게 동작합니다.

1.2.2 추출자(Extractor) — 선언적 요청 파싱

추출자는 Axum의 가장 독특하고 강력한 기능입니다. 핸들러 함수의 매개변수로 특정 타입을 적으면, Axum이 자동으로 요청에서 해당 데이터를 추출해 줍니다. 이를 통해 요청 파싱 코드가 선언적이고 간결해집니다.

use axum::{
    extract::{Path, Query, State},   // 각종 추출자들을 가져옵니다.
    Json,                             // JSON 바디를 다루는 추출자/응답 타입
};
use serde::Deserialize;

// 쿼리 파라미터를 매핑할 구조체입니다.
// serde의 Deserialize를 구현해야 Query 추출자가 파싱할 수 있습니다.
#[derive(Deserialize)]
struct PaginationQuery {
    // page와 limit은 쿼리스트링에서 ?page=1&limit=10 형태로 옵니다.
    page: Option<u32>,     // Option이므로 생략 가능합니다.
    limit: Option<u32>,
}

// 경로 매개변수를 매핑할 구조체입니다.
#[derive(Deserialize)]
struct UserPath {
    // /users/{user_id} 경로의 user_id를 추출합니다.
    user_id: u64,
}

// 핸들러 함수 — 매개변수 순서대로 추출자가 동작합니다.
// 주의: 요청 본문을 소비하는 Json 같은 FromRequest 추출자는
//       항상 마지막에 와야 합니다 (본문은 한 번만 읽을 수 있기 때문입니다).
async fn get_user(
    State(db): State<Db>,                              // 앱 상태
    Path(UserPath { user_id }): Path<UserPath>,        // 경로 매개변수
    Query(pagination): Query<PaginationQuery>,         // 쿼리스트링
) -> Json<User> {
    // 추출자가 모든 파싱을 끝냈으므로 비즈니스 로직만 작성하면 됩니다.
    let page = pagination.page.unwrap_or(1);
    let limit = pagination.limit.unwrap_or(20);
    let user = db.find_user(user_id, page, limit).await;
    Json(user)
}

위 예에서 볼 수 있듯이, 핸들러는 단지 매개변수를 선언하기만 하면 됩니다. 요청 본문을 직접 읽고 파싱하는 코드를 작성할 필요가 없습니다. 이는 코드를 읽기 쉽게 만들 뿐 아니라, 파싱 로직의 재사용성도 높여줍니다.

1.2.3 tower와의 완벽한 통합

Axum이 다른 프레임워크와 구별되는 가장 큰 특징은 자체 미들웨어 시스템이 없다는 것입니다. 대신 tower::Service 트레이트를 사용합니다. 이는 단순한 선택이 아니라 강력한 전략입니다. tower 생태계에는 이미 수많은 미들웨어와 유틸리티가 구현되어 있기 때문입니다.

  • tower::timeout::TimeoutLayer — 요청 처리 시간 제한
  • tower::limit::ConcurrencyLimitLayer — 동시 요청 수 제한
  • tower::load_shed::LoadShedLayer — 큐가 가득 차면 요청 거부
  • tower_http::trace::TraceLayer — 요청/응답 로깅
  • tower_http::compression::CompressionLayer — 응답 압축
  • tower_http::cors::CorsLayer — CORS 헤더 처리
  • tower_http::auth::ValidateRequestHeaderLayer — 인증

이 미들웨어들을 Axum에서 그대로 사용할 수 있을 뿐 아니라, hyper나 tonic(다른 tokio 생태계 도구)으로 만든 애플리케이션과도 미들웨어를 공유할 수 있습니다. 이는 학습 곡선을 줄이고 코드 재사용성을 극대화합니다.

1.3 다른 프레임워크와의 비교

Rust 웹 생태계의 주요 프레임워크들을 비교해 보면 Axum의 위치를 더 명확히 이해할 수 있습니다. 아래 표는 핵심 특징을 요약한 것입니다.

프레임워크라우팅 방식미들웨어주요 철학활성도
Axum함수 체이닝tower::Serviceergonomics + modularity매우 활발
Actix-web매크로/어트리뷰트자체 시스템성능 우선활발
Rocket매크로(#[get])Fairings개발자 편의성활발
WarpFilter 조합Filter 체인함수형 프로그래밍보통
Tide함수 체이닝미들웨어 트레이트단순함느림

Axum은 Warp의 함수형 접근에서 영감을 받았지만, 더 직관적인 API를 제공합니다. Actix-web과 비교하면 성능은 비슷하지만(둘 다 hyper 기반), tower 생태계와의 호환성이 더 좋습니다. Rocket은 사용성이 뛰어나지만 async 지원이 비교적 늦게 추가되었습니다.

【팁】 프레임워크 선택은 팀의 경험과 프로젝트 요구사항에 따라 달라집니다. 하지만 Rust의 공식 비동기 런타임인 tokio를 만드는 팀이 Axum을 관리한다는 점은, 장기적인 안정성과 지원 측면에서 큰 장점입니다.

1.4 Axum의 성능 특성

Axum은 hyper 위에 얇은 레이어로 동작합니다. 즉, HTTP 파싱과 TCP 처리는 hyper가 담당하고, Axum은 라우팅과 핸들러 호출만 추가합니다. 따라서 성능 오버헤드가 매우 적습니다. TechEmpower 벤치마크에서 Axum 기반 애플리케이션은 상위권에 위치합니다.

다만 성능은 프레임워크 자체보다 애플리케이션 설계에 더 큰 영향을 받습니다. 데이터베이스 쿼리 최적화, 적절한 캐싱, 비동기 I/O의 올바른 사용이 훨씬 더 중요합니다. 이 책의 후반부에서 성능 최적화 기법을 자세히 다루겠습니다.

1.5 안전성과 신뢰성

Axum은 100% 안전한 Rust(#![forbid(unsafe_code)])로 작성되었습니다. 즉, 메모리 안전 버그가 발생할 수 있는 unsafe 블록을 일절 사용하지 않는다는 뜻입니다. 이는 보안에 민감한 웹 서버에서 중요한 장점입니다. 또한 Rust의 강력한 타입 시스템 덕분에, 런타임이 아닌 컴파일 타임에 많은 오류를 잡을 수 있습니다.

예를 들어, 핸들러가 State<AppState>를 요구하는데 라우터에 with_state를 호출하지 않았다면 컴파일 에러가 발생합니다. 라우트 경로의 매개변수 개수와 Path 추출자의 필드 개수가 맞지 않아도 컴파일 에러가 납니다. 이런 ’컴파일 타임 검증’은 프로덕션 환경에서의 안정성을 크게 높여줍니다.

1.6 이 책의 구성과 학습 방법

이 책은 다섯 부분으로 구성되어 있습니다. 각 부분은 독자의 수준에 맞춰 점진적으로 심화됩니다.

  1. 제1부 Axum 입문: 설치, 첫 앱, 라우팅 기초, 간단한 핸들러
  2. 제2부 핵심 개념: 추출자, 상태 관리, 미들웨어, 에러 처리
  3. 제3부 실전 구축: REST API, 데이터베이스, 템플릿, 파일 업로드
  4. 제4부 고급 기법: 웹소켓, SSE, 인증, TLS, HTTP/2, 관측성
  5. 제5부 프로젝트와 베스트 프랙티스: 풀스택 예제, 테스팅, 배포

초보자는 1부부터 순서대로 읽기를 권합니다. 웹 개발 경험이 있는 분은 2부부터 시작해도 무방합니다. 각 장은 이론 설명과 함께 풍부한 코드 예제를 제공하며, 모든 코드에는 한국어 주석을 달아두었습니다. 코드를 직접 타이핑해 보면서 학습하면 더 효과적입니다.

【중요】 이 책의 모든 예제는 Axum 0.8.x를 기준으로 작성되었습니다. Axum은 활발히 개발 중이므로 일부 API가 변경될 수 있습니다. 최신 정보는 항상 공식 문서(docs.rs/axum)를 확인하세요.

1.7 요약

이 장에서는 Axum이 무엇인지, 왜 Rust 웹 생태계에서 주목받는지 살펴봤습니다. 핵심은 다음과 같습니다. Axum은 매크로 없는 직관적인 API, 강력한 추출자 시스템, tower 생태계와의 완벽한 통합을 통해 Rust로 웹 서버를 구축하는 가장 현대적인 방법을 제공합니다. 다음 장에서는 실제로 Axum 개발 환경을 구축하고 첫 애플리케이션을 실행해 보겠습니다.

로그인하고 진행률 저장<- 시리즈 목록으로 돌아가기
다음 챕터 (🔒) ->
2장. 개발 환경 구축 — Rust와 Axum 시작하기